package com.tree.rpc.netty.registry;

import com.tree.rpc.netty.core.msg.InvokeMsg;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName com.tree.rpc.netty.registry
 * Description: <类功能描述>. <br>
 * <p>
 * 处理整个注册中心的业务逻辑
 * </p>
 * @Author tree
 * @Date 2019-11-06 21:03
 * @Version 1.0
 */
public class RegistryHandler extends ChannelHandlerAdapter {

    /**
     * 在注册中心的服务需要有一个容器存放
     */
    private static Map<String,Object> registryMap = new ConcurrentHashMap<String, Object>();


    private List<String> classCache = new ArrayList<String>();

    /**
     * 约定，只要写在provider包下面的所有类都认为是一个可对外提供服务的实现类
     * //TODO 后期改为从Zookeeper获取
     */
    public RegistryHandler(){
        scanClass("com.tree.rpc.netty.provider");
        doRegister();
    }



    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Object result = new Object();

        //客户端传过来的调用信息
        InvokeMsg request = (InvokeMsg) msg;

        if(registryMap.containsKey(request.getFullClassName())){
            Object clazz = registryMap.get(request.getFullClassName());
            Method method = clazz.getClass().getMethod(request.getMethodName(),request.getParams());
            result= method.invoke(clazz,request.getValues());
        }

        /**
         * 将接收到的消息 写给发送者，并冲刷出站消息
         */
        ctx.writeAndFlush(result);
        ctx.close();

    }

//    /**
//     *  将未决消息冲刷到 远程节点，并且关 闭该 Channel
//     * @param ctx
//     */
//    @Override
//    public void channelReadComplete(ChannelHandlerContext ctx) {
//        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER) .addListener(ChannelFutureListener.CLOSE);
//    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    /**
     * 把扫描到class实例化，放到map中，这就是注册过程
     * 注册的服务名称，叫接口名字
     * 约定优于配置
     */
    private void doRegister() {
        if(classCache.size() == 0) {
            return;
        }

        classCache.forEach(className->{
            try {
                Class<?> clazz = Class.forName(className);
                //服务名称
                //TODO 可以改为annotation， 获取annotation的值
                Class<?> interfaces = clazz.getInterfaces()[0];
                registryMap.put(interfaces.getName(),clazz.newInstance());

            }catch (Exception e){
                e.printStackTrace();

            }
        });


    }

    private void scanClass(String packageName) {
        URL url = this.getClass().getClassLoader().getResource(packageName.replaceAll("\\.","/"));
        File dir = new File(url.getFile());

        for(File file : dir.listFiles()){
            if(file.isDirectory()){
                scanClass(packageName+"."+file.getName());
            }else {
                classCache.add(packageName+"."+file.getName().replace(".class","").trim());
            }
        }
    }




}
